package data;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import javax.swing.JOptionPane;

import org.jdom.DataConversionException;
import org.jdom.Element;

import fileIO.XMLParser;
import fileIO.XMLWriter;

import storage.Profile;
import storage.Rule;

public class ProfileList {
	public static Hashtable<String, Profile> profileList;
	private static boolean initialized =false;
	
	@SuppressWarnings("unchecked")
	public static void initialize(){
		if(!initialized){
			profileList = new Hashtable<String, Profile>();
			initialized = true;
			//Read in from external data source and populate fields
			Element root = XMLParser.parseDocument(FilePath.PROFILE_LIST);
			if(root ==null){
				//JOptionPane.showMessageDialog(null, "Profile List file not found, create a profile to save a new file");
			}else{
				//Root has data for each profile create a new profile object and add to list
				for(int profileCount = 0;profileCount<root.getChildren().size();profileCount++){
					Profile profile = new Profile();
					Element profileNode = (Element)root.getChildren().get(profileCount);
					try {
						profile.active = profileNode.getAttribute("enabled").getBooleanValue();
					} catch (DataConversionException e1) {
						JOptionPane.showMessageDialog(null, "Malformed Profile XML File, terminating");
					}
					Element companyInfoNode = (Element)profileNode.getChild("COMPANY_INFO");
					Element topoInfoNode = (Element)profileNode.getChild("TOPO_INFO");
					Element billingInfoNode = (Element)profileNode.getChild("BILLING_INFO");
					Element rulesNode = (Element)profileNode.getChild("RULES");
					
					profile.profileName = profileNode.getChildText("NAME");
					//process company info
					profile.cnee = companyInfoNode.getChildText("CNEE");
					Element addressNode = companyInfoNode.getChild("ADDRESS");
					profile.street = addressNode.getChildText("STREET");
					profile.city = addressNode.getChildText("CITY");
					profile.state = addressNode.getChildText("STATE");
					profile.zip = addressNode.getChildText("ZIP");
					profile.country = addressNode.getChildText("COUNTRY");
					profile.telephone = companyInfoNode.getChildText("TELEPHONE");
					profile.email = companyInfoNode.getChildText("EMAIL");
					profile.contact = companyInfoNode.getChildText("CONTACT");

					//process TOPO Info
					profile.originEmployeeMap = new HashMap<String,ArrayList<String>>();
					List<Element> originList = topoInfoNode.getChildren("ORIGIN_OFFICE");
					for(int i=0;i<originList.size();i++){
						List<Element> originCSList = originList.get(i).getChildren("CS");
						ArrayList<String> empList = new ArrayList<String>();
						for(int z=0;z<originCSList.size();z++){
							empList.add(originCSList.get(z).getAttributeValue("name"));
						}
						profile.originEmployeeMap.put(originList.get(i).getAttributeValue("name"), empList);
					}
					profile.originEmployeeMap = cleanEmployeeList(profile.originEmployeeMap, true);
					
					profile.destEmployeeMap = new HashMap<String,ArrayList<String>>();
					List<Element> destList = topoInfoNode.getChildren("DEST_OFFICE");
					for(int i=0;i<destList.size();i++){
						List<Element> destCSList = destList.get(i).getChildren("CS");
						ArrayList<String> empList = new ArrayList<String>();
						for(int z=0;z<destCSList.size();z++){
							empList.add(destCSList.get(z).getAttributeValue("name"));
						}
						profile.destEmployeeMap.put(destList.get(i).getAttributeValue("name"), empList);
					}
					profile.destEmployeeMap = cleanEmployeeList(profile.destEmployeeMap, false);
					
					profile.saleHandler = topoInfoNode.getChildText("SALES_MEMBER");
					
					//Process Billing Info
					profile.chargePerContainer = Double.parseDouble(billingInfoNode.getChildText("CHARGE_PER_CONTAINER"));
					profile.term = Integer.parseInt(billingInfoNode.getChildText("TERM"));
					profile.daysAfter = billingInfoNode.getChildText("DAYS_AFTER");
					profile.billTo = billingInfoNode.getChildText("BILL_TO");
					profile.companyType = billingInfoNode.getChildText("COMPANY_TYPE");
					
					for(int ruleCount =0;ruleCount<rulesNode.getChildren().size();ruleCount++){
						Element ruleNode = (Element)rulesNode.getChildren().get(ruleCount);
						Rule rule = new Rule(ruleNode.getChildText("NAME"));
						try {
							rule.active = ruleNode.getAttribute("enabled").getBooleanValue();
						} catch (DataConversionException e) {
							JOptionPane.showMessageDialog(null, "Malformed Profile XML File, terminating program.");
						}
						rule.groupNo = Integer.parseInt(ruleNode.getChildText("GROUP_NO"));
						rule.connector = ruleNode.getChildText("CONNECTOR");
						rule.subjectField = ruleNode.getChildText("SUBJECT_FIELD");
						rule.value = ruleNode.getChildText("VALUE");
						rule.equality = ruleNode.getChildText("EQUALITY");
						rule.targetField = ruleNode.getChildText("TARGET_FIELD");
						
						if(profile.ruleList.containsKey(rule.field)){
							profile.ruleList.get(rule.field).add(rule);
						}else{
							ArrayList<Rule> temp = new ArrayList<Rule>();
							temp.add(rule);
							profile.ruleList.put(rule.field, temp);
						}
					}
					profileList.put(profile.profileName, profile);
				}
			}
		}
	}
	public static void save(){
		//saves the current profileList to external data source
		Element root = new Element("PROFILE_LIST");
		
		Object[] keySet = profileList.keySet().toArray();
		for(int profileCount =0; profileCount < keySet.length;profileCount++){
			Profile profile = profileList.get(keySet[profileCount]);
			Element profileNode  = new Element("PROFILE");
			profileNode.setAttribute("enabled",Boolean.toString(profile.active));
			profileNode.addContent(new Element("NAME").setText(profile.profileName));
			
			{
				Element companyInfoNode = new Element("COMPANY_INFO");
				companyInfoNode.addContent(new Element("CNEE").setText(profile.cnee));
				{
					Element addressNode = new Element("ADDRESS");
					addressNode.addContent(new Element("STREET").setText(profile.street));
					addressNode.addContent(new Element("CITY").setText(profile.city));
					addressNode.addContent(new Element("STATE").setText(profile.state));
					addressNode.addContent(new Element("ZIP").setText(profile.zip));
					addressNode.addContent(new Element("COUNTRY").setText(profile.country));
					companyInfoNode.addContent(addressNode);
				}
				companyInfoNode.addContent(new Element("TELEPHONE").setText(profile.telephone));
				companyInfoNode.addContent(new Element("EMAIL").setText(profile.email));
				companyInfoNode.addContent(new Element("CONTACT").setText(profile.contact));
				profileNode.addContent(companyInfoNode);
			}
			//Write TOPO Info node
			{
				Element topoInfoNode = new Element("TOPO_INFO");
				
				HashMap<String, ArrayList<String>> origList = cleanEmployeeList(profile.originEmployeeMap, true);
				if(origList!=null){
					Object[] officeKeySet = origList.keySet().toArray();
					for(int oKeyCount = 0; oKeyCount<officeKeySet.length; oKeyCount++){
						Element originOfficeNode = new Element("ORIGIN_OFFICE");
						if((String)officeKeySet[oKeyCount] != null){
							originOfficeNode.setAttribute("name",(String)officeKeySet[oKeyCount]);
							
							ArrayList<String> originEmpList = origList.get(officeKeySet[oKeyCount]);
							for(int oEmpCount = 0;oEmpCount< originEmpList.size();oEmpCount++){
								Element csNode = new Element("CS");
								csNode.setAttribute("name",originEmpList.get(oEmpCount));
								originOfficeNode.addContent(csNode);
							}
							topoInfoNode.addContent(originOfficeNode);
						}
					}
				}	
				HashMap<String, ArrayList<String>> destList = cleanEmployeeList(profile.destEmployeeMap, false);
				if(destList!=null){
					Object[] officeKeySet = destList.keySet().toArray();
					for(int oKeyCount = 0; oKeyCount<officeKeySet.length; oKeyCount++){
						Element destOfficeNode = new Element("DEST_OFFICE");
						if((String)officeKeySet[oKeyCount] != null){
							destOfficeNode.setAttribute("name",(String)officeKeySet[oKeyCount]);
							
							ArrayList<String> destEmpList = destList.get(officeKeySet[oKeyCount]);
							for(int oEmpCount = 0;oEmpCount< destEmpList.size();oEmpCount++){
								Element csNode = new Element("CS");
								csNode.setAttribute("name",destEmpList.get(oEmpCount));
								destOfficeNode.addContent(csNode);
							}
							topoInfoNode.addContent(destOfficeNode);
						}
					}
				}
				topoInfoNode.addContent(new Element("SALES_MEMBER").setText(profile.saleHandler));
				profileNode.addContent(topoInfoNode);
			}
			//Write billing Info
			{
				Element billingInfoNode = new Element("BILLING_INFO");
				billingInfoNode.addContent(new Element("CHARGE_PER_CONTAINER").setText(Double.toString(profile.chargePerContainer)));
				billingInfoNode.addContent(new Element("TERM").setText(Integer.toString((profile.term))));
				billingInfoNode.addContent(new Element("DAYS_AFTER").setText(profile.daysAfter));
				billingInfoNode.addContent(new Element("BILL_TO").setText(profile.billTo));
				billingInfoNode.addContent(new Element("COMPANY_TYPE").setText(profile.companyType));
				profileNode.addContent(billingInfoNode);
			}
			//Write rules Node
			{
				Element rulesNode = new Element("RULES");
				Object[] ruleKeys = profile.ruleList.keySet().toArray();
				for(int ruleCount =0;ruleCount<ruleKeys.length;ruleCount++){
					
					ArrayList<Rule> tempRuleList = profile.ruleList.get(ruleKeys[ruleCount]);
					for(int i =0;i<tempRuleList.size();i++){
						Element ruleNode = new Element("RULE");
						ruleNode.setAttribute("enabled",Boolean.toString(tempRuleList.get(i).active));
						ruleNode.addContent(new Element("NAME").setText(tempRuleList.get(i).field));
						ruleNode.addContent(new Element("GROUP_NO").setText(Integer.toString(tempRuleList.get(i).groupNo)));
						ruleNode.addContent(new Element("CONNECTOR").setText(tempRuleList.get(i).connector));
						ruleNode.addContent(new Element("SUBJECT_FIELD").setText(tempRuleList.get(i).subjectField));
						ruleNode.addContent(new Element("VALUE").setText(tempRuleList.get(i).value));
						ruleNode.addContent(new Element("EQUALITY").setText(tempRuleList.get(i).equality));
						ruleNode.addContent(new Element("TARGET_FIELD").setText(tempRuleList.get(i).targetField));
						rulesNode.addContent(ruleNode);
					}
				}
				profileNode.addContent(rulesNode);
			}
			root.addContent(profileNode);
		}
		XMLWriter.writeDocument(root, FilePath.PROFILE_LIST);
	}
	/**
	 * Removes all invalid entries in the employeeList 
	 * @param input
	 */
	public static HashMap<String,ArrayList<String>> cleanEmployeeList(HashMap<String,ArrayList<String>> input, boolean origin){
		HashMap<String,ArrayList<String>> output = new HashMap<String,ArrayList<String>>();
		
		Object[] keyList = input.keySet().toArray();
		for(int i=0;i<keyList.length;i++){
			ArrayList<String> temp = input.get(keyList[i]);
				
			ArrayList<String> dataList = EmployeeInfo.getEmployeeNames((String)keyList[i]);
			if(dataList==null||dataList.size()==0)
				continue;

			if(EmployeeInfo.isOrigin((String)keyList[i])!=origin)
				continue;
			
			for(int z=0;z<temp.size();z++){
				if(dataList.contains(temp.get(z))){
					ArrayList<String> tempStor = output.get(keyList[i]);
					if(tempStor==null){
						tempStor = new ArrayList<String>();
						output.put((String) keyList[i], tempStor);
					}
					tempStor.add(temp.get(z));
				}
			}
		}
		return output;
	}
}
